--[[
Copyright (C) 2008-2009 Adirelle

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--]]

if not Yatba then return end
local Yatba = Yatba

local LibSharedMedia = LibStub("LibSharedMedia-3.0")
local AceConfigRegistry = LibStub("AceConfigRegistry-3.0")
local LibBars = LibStub("LibBars-1.0")

local MEDIA_FONT = LibSharedMedia.MediaType.FONT
local MEDIA_STATUSBAR = LibSharedMedia.MediaType.STATUSBAR

local pairs, next, type, error, assert = pairs, next, type, error, assert
local bars, groups, watchedGUIDs = Yatba.bars, Yatba.groups, Yatba.watchedGUIDs

--------------------------------------------------------------------------------
-- Database upvalue
--------------------------------------------------------------------------------

local db
Yatba.RegisterSignal('GroupsDB', 'DatabaseSet', function() db = Yatba.db.profile end)

--------------------------------------------------------------------------------
-- Derivated group prototype
--------------------------------------------------------------------------------

local backdropDefault = {
	bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
	edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
	inset = 4,
	edgeSize = 8,
	tile = true,
	insets = {left = 2, right = 2, top = 2, bottom = 2}
}

local groupPrototype = setmetatable(
	{ super = LibBars.barListPrototype },
	{ __index = LibBars.barListPrototype }
)
groupPrototype.metatable = { __index = groupPrototype }

function groupPrototype:GetBackdrop()
	local backdrop = self.backdrop
	if not backdrop then
		self.backdrop = CreateFrame("Button", nil, self)
		backdrop = self.backdrop
		backdrop:SetBackdrop(backdropDefault)
		backdrop:SetBackdropColor(0.5, 0.5, 0.5, 0.5)
		backdrop:SetFrameStrata("BACKGROUND")
		backdrop:EnableMouse(false)
		if groupPrototype.super.IsAnchorVisible(self) then
			backdrop:Show()
		else
			backdrop:Hide()
		end
	end
	return backdrop
end

function groupPrototype:SortBars()
	groupPrototype.super.SortBars(self)
	self:UpdateBackdropLayout()
end

function groupPrototype:UpdateOrientationLayout()
	groupPrototype.super.UpdateOrientationLayout(self)
	self:UpdateBackdropLayout()
end

function groupPrototype:SetMaxBars(num)
	groupPrototype.super.SetMaxBars(self, num)
	self:UpdateBackdropLayout()
end

function groupPrototype:UpdateBackdropLayout()
	local backdrop = self:GetBackdrop()
	local n, spacing = self:GetMaxBars(), self:GetSpacing()
	if not n or n == 0 then
		n = 5
	end
	local thickness = (self:GetThickness() + spacing) * n - spacing
	local point
	if self:IsVertical() then
		backdrop:SetWidth(thickness)
		backdrop:SetHeight(self:GetLength())
		point = self:HasReverseGrowth() and 'RIGHT' or 'LEFT'
	else
		backdrop:SetWidth(self:GetLength())
		backdrop:SetHeight(thickness)
		point = self:HasReverseGrowth() and 'BOTTOM' or 'TOP'
	end
	backdrop:ClearAllPoints()
	backdrop:SetPoint(point, self, point)
end

function groupPrototype:ShowAnchor()
	self.backdrop:Show()
	groupPrototype.super.ShowAnchor(self)
end

function groupPrototype:HideAnchor()
	self.backdrop:Hide()
	groupPrototype.super.HideAnchor(self)
end

function groupPrototype:IsAnchorVisible()
	return self.backdrop:IsVisible() and groupPrototype.super.IsAnchorVisible(self)
end

--------------------------------------------------------------------------------
-- Group handling
--------------------------------------------------------------------------------

local function RecordGroupPosition(event, group, x, y)
	group.db.x = x
	group.db.y = y
	AceConfigRegistry:NotifyChange(Yatba.name)	
end

function Yatba:CreateHeader(event, timer)
	local group = timer and timer.group
	if not group.db.displayHeaders then
		return
	end
	local headerBar = group:GetBar(timer.unitGUID)
	local header = headerBar and bars[headerBar]
	if not header then
		--Yatba:Debug('Creating header for %q in group %q', timer, group.name)
		header = Yatba.barPrototypes.header:Create(group, timer.unitGUID, timer:GetUnitId(), timer.displayName)
		header:SetRaidIcon(timer.raidIcon)
		group:SortBars()
	end
	header:AddTimer(timer)
end

local function BarSortFunc(barA, barB)
	local a, b = barA and bars[barA], barB and bars[barB]
	if a and b then
		return a:IsLesserThan(b)
	else
		return not b
	end
end

local function UpdateThickness(group)
	group:SetThickness(db.thickness)
end

local function AuraFilterUpdated(group)
	Yatba:UpdateFilter(group)
end

function Yatba:InitializeGroup(name, reload)
	if not db.groups[name] then
		-- if the group config is not a table, force AceDB to
		-- recreate a brand new table with default values
		db.groups[name] = nil
	end
	local def = db.groups[name]
	local group = self:GetBarGroup(name)
	if not group then
		group = self:NewBarGroup(name, def.orientation, def.length, db.thickness, 'Yatba-'..name)
		setmetatable(group, groupPrototype.metatable)
		group:SetSortFunction(BarSortFunc)
		group:UpdateBackdropLayout()
	end
	groups[name] = group
	group.db = def
	group.RegisterCallback(self, "AnchorMoved", RecordGroupPosition)
	self.RegisterSignal(group, 'ConfigChanged_thickness', UpdateThickness, group)
	self.RegisterSignal(group, 'TimerAdded_'..name, self.CreateHeader, self)
	self.RegisterSignal(group, 'AuraFilterUpdated', AuraFilterUpdated, group)

	if not def.x then
		group:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
		def.x, def.y = group:GetLeft(), group:GetTop()
	end
	group:ClearAllPoints()
	group:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", def.x, def.y)

	group:SetAlpha(def.alpha)
	group:SetFill(def.fill)
	group:ReverseGrowth(def.reverseGrowth)
	group:SetMaxBars(def.maxBars)
	group:SetFont(LibSharedMedia:Fetch(MEDIA_FONT, db.font), db.fontSize, db.fontFlags)
	group:SetTexture(LibSharedMedia:Fetch(MEDIA_STATUSBAR, db.statusbar))
	group:SetScale(def.scale)

	group:SetOrientation(def.orientation)
	group:SetLength(def.length)
	group:SetThickness(db.thickness)
	
	if reload then
		group:Lock()
		group:HideAnchor()
	else
		group:Unlock()
		group:ShowAnchor()
	end
	if not def.enable then
		group:Hide()
	end

	self:UpdateFilter(group)

	self:AddGroupOption(group, name)
end

function Yatba:ReleaseGroup(group)
	local name = group.name
	group.UnregisterAllCallbacks(self)
	self.UnregisterAllSignals(group)
	self:SendSignal('GroupDisabled_'..name)
	group:Hide()
	self:RemoveGroupOption(name, group)
	group.db = nil
	groups[name] = nil
end

function Yatba:RemoveGroup(name)
	local group = groups[name]
	if group then
		self:ReleaseGroup(group)
	end
	if db.groups[name].isDefault then
		db.groups[name] = false
	else
		db.groups[name] = nil
	end
end

function Yatba:AddHeaders(group)
	for name,bar in group:IterateBars() do
		self:CreateHeader(nil, bars[bar])
	end
end

function Yatba:IsGroupEnabled(name)
	return db.groups[name] and db.groups[name].enable
end

function Yatba:SetGroupEnabled(name, enable)
	if not db.groups[name] then return end
	db.groups[name].enable = enable
	local group = groups[name]
	if enable then
		group:Show()
		self:RefreshUnitTimers()
	else
		group:Hide()
		self:SendSignal('GroupDisabled_'..name)
	end
end

do
	local tmp = {}
	function Yatba:GetGroupList()
		for k in pairs(tmp) do tmp[k] = nil end
		for name in pairs(db.groups) do
			tmp[name] = name
		end
		return tmp
	end
end
